﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.ServiceRuntime;
using DeepTime.DL;
using Microsoft.WindowsAzure.StorageClient;
using System.IO;
using Microsoft.DeepZoomTools;
using System.Xml.Linq;
using DeepTime.DataSources.DL;
using DeepTime.DL.DataModels;
using DeepTime.DL.DataSources;
using System.Windows;

namespace DeepTime.DeepZoomGenerator
{
    public class DeepZoomGenerator
    {
        public static void CreateImageDeepZoom(string UploadedImageMetaDataPartitionKey, string UploadedImageMetaDataRowKey)
        {
            //
            // Get uploaded image meta data from table storage
            //
            UploadedImageMetaDataDataSource uploadedImageMetaDataDataSource = new UploadedImageMetaDataDataSource();
            UploadedImageMetaDataDataModel uploadedImageMetaData = uploadedImageMetaDataDataSource.Select().Where(img => img.PartitionKey == UploadedImageMetaDataPartitionKey && img.RowKey == UploadedImageMetaDataRowKey).FirstOrDefault();

            if (uploadedImageMetaData == null)
            {
                throw new Exception("Aziz Light!");
            }

            //
            // Get Reference to local storage
            //
            LocalResource localStorage = RoleEnvironment.GetLocalResource("DeepZoomTempStorage");

            //
            // Create temp folder in local storage that will be used for storing temp files
            //
            DirectoryInfo tempDir = new DirectoryInfo(Path.Combine(localStorage.RootPath, System.Guid.NewGuid().ToString()));
            tempDir.Create();

            //
            // Get Blob
            //
            UploadedImageDataSource uploadedImageDataSource = new UploadedImageDataSource();
            CloudBlockBlob uploadedImageBlob = uploadedImageDataSource.Select(uploadedImageMetaData.BlobUri);

            //
            // Write blob to local storage
            //
            FileInfo sourceImage = new FileInfo(Path.Combine(tempDir.FullName, "source_image.jpg"));
            FileStream fs = sourceImage.OpenWrite();
            uploadedImageBlob.DownloadToStream(fs);
            fs.Close();

            //
            // Generate DeepZoom
            //
            ImageCreator ic = new ImageCreator()
            {
                TileSize = 256,
                TileFormat = ImageFormat.Jpg,
                ImageQuality = 0.95,
                TileOverlap = 0
            };
            
            string deepZoomUID = System.Guid.NewGuid().ToString().ToLower();
            string target = Path.Combine(tempDir.FullName, deepZoomUID);

            ic.Create(sourceImage.FullName, target);

            //
            // Get dimensions form the generated xml file
            //
            XDocument doc = XDocument.Load(Path.Combine(tempDir.FullName, deepZoomUID + ".xml"));
            int height = Convert.ToInt32(doc.Root.Element("{http://schemas.microsoft.com/deepzoom/2009}Size").Attribute("Height").Value);
            int width = Convert.ToInt32(doc.Root.Element("{http://schemas.microsoft.com/deepzoom/2009}Size").Attribute("Width").Value);

            //
            // Save generated DeepZoom to blob storage
            //
            Directory.Move(target + "_files", target);

            DeepZoomImageDataSource deepZoomImageDataSource = new DeepZoomImageDataSource();
            foreach (string item in Directory.GetFiles(target, "*.jpg", SearchOption.AllDirectories))
            {
                FileInfo fi = new FileInfo(item);
                //
                // Build BlobUID which includes a sub directory structure mirroring the path of the image relative to the local temp dir
                //
                string relativeImagePath = fi.FullName.Replace(tempDir.FullName, "").Replace("\\", "/").TrimStart('/');
                string BlobUID = relativeImagePath;

                //
                // Put image to blob
                //
                CloudBlockBlob Blob;
                deepZoomImageDataSource.Insert(fi.OpenRead(), BlobUID, out Blob);

                //
                // Set Metadata and properties of blob
                //
                //Blob.Metadata["FileName"] = "";
                //Blob.SetMetadata();

                Blob.Properties.ContentType = "image/jpeg";
                Blob.Properties.ContentEncoding = "Unicode (UTF-8)";
                Blob.SetProperties();
            }

            //
            // Get the uri for the folder that all the deepzoom blobs are stored in
            //
            string deepZoomBlobUri = deepZoomImageDataSource.GetDirectoryReference(deepZoomUID).Uri.OriginalString;

            //
            // Create deepzoom image meta data and persist it
            //
            DeepZoomImageMetaDataDataSource deepZoomImageMetaDataDataSource = new DeepZoomImageMetaDataDataSource();
            DeepZoomImageMetaDataDataModel deepZoomImageMetaData = new DeepZoomImageMetaDataDataModel()
            {
                PartitionKey = "1",
                RowKey = System.Guid.NewGuid().ToString(),
                Timestamp = DateTime.Now,
                BlobUri = deepZoomBlobUri,
                Height = height,
                Width = width
            };

            deepZoomImageMetaDataDataSource.Insert(deepZoomImageMetaData);

            //
            // Delete temp data from the local storage
            //
            try
            {
                tempDir.Delete(true);
            }
            catch
            {
            }
        }

        public static void CreateSparseImageDeepZoom(string UploadedImageCollageMetaDataPartitionKey)
        {
            //
            // Get uploaded image collage meta data from table storage
            //
            UploadedImageCollageMetaDataDataSource uploadedImageCollageMetaDataDataSource = new UploadedImageCollageMetaDataDataSource();
            IEnumerable<UploadedImageCollageMetaDataDataModel> uploadedImageCollagesMetaData = uploadedImageCollageMetaDataDataSource.Select().Where(img => img.PartitionKey == UploadedImageCollageMetaDataPartitionKey);

            if (uploadedImageCollagesMetaData.Count() == 0)
            {
                throw new Exception("Aziz Light!");
            }

            //
            // Get Reference to local storage
            //
            LocalResource localStorage = RoleEnvironment.GetLocalResource("DeepZoomTempStorage");

            //
            // Create temp folders in local storage that will be used for storing temp files
            //
            DirectoryInfo tempDir = new DirectoryInfo(Path.Combine(localStorage.RootPath, System.Guid.NewGuid().ToString()));
            DirectoryInfo tempUploadedImagesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, "uploadedImages"));
            tempDir.Create();
            tempUploadedImagesDir.Create();

            //
            // Calculate viewport width
            //
            UploadedImageCollageMetaDataDataModel rightMostImage = uploadedImageCollagesMetaData.OrderByDescending(img => img.X).FirstOrDefault();
            UploadedImageCollageMetaDataDataModel bottomMostImage = uploadedImageCollagesMetaData.OrderByDescending(img => img.Y).FirstOrDefault();

            if (rightMostImage == null)
            {
                throw new Exception("Aziz Light! #2");
            }

            double viewPortWidth = Math.Ceiling((Math.Max(rightMostImage.X, bottomMostImage.Y) + 200) / 200);

            //
            // Get Blobs, store them in the temp uploaded images folder and create list of deepzoom images
            //
            List<Image> images = new List<Image>();
            UploadedImageDataSource uploadedImageDataSource = new UploadedImageDataSource();

            foreach (UploadedImageCollageMetaDataDataModel item in uploadedImageCollagesMetaData.Reverse())
            {
                //
                // Get blob reference
                //
                CloudBlockBlob uploadedImageBlob = uploadedImageDataSource.Select(item.BlobUri);

                //
                // Write blob to local storage
                //
                string tempPath = Path.Combine(tempUploadedImagesDir.FullName, item.RowKey + ".jpg");
                FileInfo sourceImage = new FileInfo(tempPath);
                FileStream fs = sourceImage.OpenWrite();
                uploadedImageBlob.DownloadToStream(fs);
                fs.Close();

                //
                // Create deepzoom image
                //
                double ViewPortOriginX = Math.Min(item.X / 200 * -1, 0);
                double ViewPortOriginY = Math.Min(item.Y / 200 * -1, 0);
                Image image = new Image(tempPath)
                {
                    ViewportWidth = viewPortWidth,
                    ViewportOrigin = new Point(ViewPortOriginX, ViewPortOriginY)
                };

                images.Add(image);
            }

            //
            // Generate Sparse deepzoom
            //
            SparseImageCreator ic = new SparseImageCreator()
            {
                TileSize = 256,
                TileFormat = ImageFormat.Jpg,
                ImageQuality = 0.95,
                TileOverlap = 0,
            };

            string deepZoomUID = System.Guid.NewGuid().ToString().ToLower();
            string target = Path.Combine(tempDir.FullName, deepZoomUID);

            ic.Create(images, target);

            //
            // Get dimensions form the generated xml file
            //
            XDocument doc = XDocument.Load(Path.Combine(tempDir.FullName, deepZoomUID + ".xml"));
            int height = Convert.ToInt32(doc.Root.Element("{http://schemas.microsoft.com/deepzoom/2009}Size").Attribute("Height").Value);
            int width = Convert.ToInt32(doc.Root.Element("{http://schemas.microsoft.com/deepzoom/2009}Size").Attribute("Width").Value);

            //
            // Save generated DeepZoom to blob storage
            //
            Directory.Move(target + "_files", target);

            DeepZoomImageDataSource deepZoomImageDataSource = new DeepZoomImageDataSource();
            foreach (string item in Directory.GetFiles(target, "*.jpg", SearchOption.AllDirectories))
            {
                FileInfo fi = new FileInfo(item);
                //
                // Build BlobUID which includes a sub directory structure mirroring the path of the image relative to the local temp dir
                //
                string relativeImagePath = fi.FullName.Replace(tempDir.FullName, "").Replace("\\", "/").TrimStart('/');
                string BlobUID = relativeImagePath;

                //
                // Put image to blob
                //
                CloudBlockBlob Blob;
                deepZoomImageDataSource.Insert(fi.OpenRead(), BlobUID, out Blob);

                //
                // Set Metadata and properties of blob
                //
                //Blob.Metadata["FileName"] = "";
                //Blob.SetMetadata();

                Blob.Properties.ContentType = "image/jpeg";
                Blob.Properties.ContentEncoding = "Unicode (UTF-8)";
                Blob.SetProperties();
            }

            //
            // Get the uri for the folder that all the deepzoom blobs are stored in
            //
            string deepZoomBlobUri = deepZoomImageDataSource.GetDirectoryReference(deepZoomUID).Uri.OriginalString;

            //
            // Create deepzoom image meta data and persist it
            //
            DeepZoomImageMetaDataDataSource deepZoomImageMetaDataDataSource = new DeepZoomImageMetaDataDataSource();
            DeepZoomImageMetaDataDataModel deepZoomImageMetaData = new DeepZoomImageMetaDataDataModel()
            {
                PartitionKey = "1",
                RowKey = System.Guid.NewGuid().ToString(),
                Timestamp = DateTime.Now,
                BlobUri = deepZoomBlobUri,
                Height = height,
                Width = width
            };

            deepZoomImageMetaDataDataSource.Insert(deepZoomImageMetaData);

            //
            // Delete temp data from the local storage
            //
            try
            {
                tempDir.Delete(true);
            }
            catch
            {
            }
        }
    }
}
